home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / news / inn1.000 / inn1.4sec-linux-src.tar / inn / innd / cc.c < prev    next >
C/C++ Source or Header  |  1993-03-18  |  31KB  |  1,492 lines

  1. /*  $Revision: 1.41 $
  2. **
  3. **  Routines for the control channel.  Create a Unix-domain datagram socket
  4. **  that processes on the local server send messages to.  The control
  5. **  channel is used only by ctlinnd to tell the server to perform
  6. **  special functions.  We use datagrams so that we don't need to do an
  7. **  accept() and tie up another descriptor.  Recvfrom seems to be broken on
  8. **  several systems, so the client passes in the socket name.
  9. **
  10. **  This module completely rips away all pretense of software layering.
  11. */
  12. #include "innd.h"
  13. #include "inndcomm.h"
  14. #if    defined(DO_HAVE_UNIX_DOMAIN)
  15. #include <sys/un.h>
  16. #endif    /* defined(DO_HAVE_UNIX_DOMAIN) */
  17.  
  18.  
  19. /*
  20. **  An entry in the dispatch table.  The name, and implementing function,
  21. **  of every command we support.
  22. */
  23. typedef struct _CCDISPATCH {
  24.     char    Name;
  25.     int        argc;
  26.     STRING    (*Function)();
  27. } CCDISPATCH;
  28.  
  29.  
  30. STATIC STRING    CCaddhist();
  31. STATIC STRING    CCallow();
  32. STATIC STRING    CCbegin();
  33. STATIC STRING    CCchgroup();
  34. STATIC STRING    CCdrop();
  35. STATIC STRING    CCflush();
  36. STATIC STRING    CCflushlogs();
  37. STATIC STRING    CCgo();
  38. STATIC STRING    CChangup();
  39. STATIC STRING    CCreserve();
  40. STATIC STRING    CCmode();
  41. STATIC STRING    CCname();
  42. STATIC STRING    CCnewgroup();
  43. STATIC STRING    CCparam();
  44. STATIC STRING    CCpause();
  45. STATIC STRING    CCreaders();
  46. STATIC STRING    CCrefile();
  47. STATIC STRING    CCreject();
  48. STATIC STRING    CCreload();
  49. STATIC STRING    CCrenumber();
  50. STATIC STRING    CCrmgroup();
  51. STATIC STRING    CCsend();
  52. STATIC STRING    CCshutdown();
  53. STATIC STRING    CCsignal();
  54. STATIC STRING    CCthrottle();
  55. STATIC STRING    CCtrace();
  56. STATIC STRING    CCxabort();
  57. STATIC STRING    CCxexec();
  58.  
  59. STATIC char        CCpath[] = _PATH_NEWSCONTROL;
  60. STATIC char        **CCargv;
  61. STATIC char        CCnosite[] = "1 No such site";
  62. STATIC char        CCwrongtype[] = "1 Wrong site type";
  63. STATIC char        CCnogroup[] = "1 No such group";
  64. STATIC char        CCnochannel[] = "1 No such channel";
  65. STATIC char        CCnoreason[] = "1 Empty reason";
  66. STATIC char        CCnotrunning[] = "1 Must be running";
  67. STATIC BUFFER        CCreply;
  68. STATIC CHANNEL        *CCchan;
  69. STATIC int        CCwriter;
  70. STATIC CCDISPATCH    CCcommands[] = {
  71.     {    SC_ADDHIST,    5, CCaddhist    },
  72.     {    SC_ALLOW,    1, CCallow    },
  73.     {    SC_BEGIN,    1, CCbegin    },
  74.     {    SC_CANCEL,    1, CCcancel    },
  75.     {    SC_CHANGEGROUP,    2, CCchgroup    },
  76.     {    SC_CHECKFILE,    0, CCcheckfile    },
  77.     {    SC_DROP,    1, CCdrop    },
  78.     {    SC_FLUSH,    1, CCflush    },
  79.     {    SC_FLUSHLOGS,    0, CCflushlogs    },
  80.     {    SC_GO,        1, CCgo        },
  81.     {    SC_HANGUP,    1, CChangup    },
  82.     {    SC_MODE,    0, CCmode    },
  83.     {    SC_NAME,    1, CCname    },
  84.     {    SC_NEWGROUP,    3, CCnewgroup    },
  85.     {    SC_PARAM,    2, CCparam    },
  86.     {    SC_PAUSE,    1, CCpause    },
  87.     {    SC_READERS,    2, CCreaders    },
  88.     {    SC_REFILE,    2, CCrefile    },
  89.     {    SC_REJECT,    1, CCreject    },
  90.     {    SC_RENUMBER,    1, CCrenumber    },
  91.     {    SC_RELOAD,    2, CCreload    },
  92.     {    SC_RESERVE,    1, CCreserve    },
  93.     {    SC_RMGROUP,    1, CCrmgroup    },
  94.     {    SC_SEND,    2, CCsend    },
  95.     {    SC_SHUTDOWN,    1, CCshutdown    },
  96.     {    SC_SIGNAL,    2, CCsignal    },
  97.     {    SC_THROTTLE,    1, CCthrottle    },
  98.     {    SC_TRACE,    2, CCtrace    },
  99.     {    SC_XABORT,    1, CCxabort    },
  100.     {    SC_XEXEC,    1, CCxexec    }
  101. };
  102.  
  103.  
  104.  
  105. void
  106. CCcopyargv(av)
  107.     char        *av[];
  108. {
  109.     register char    **v;
  110.     register int    i;
  111.  
  112.     /* Get the vector size. */
  113.     for (i = 0; av[i]; i++)
  114.     continue;
  115.  
  116.     /* Get the vector, copy each element. */
  117.     for (v = CCargv = NEW(char*, i + 1); *av; av++)
  118.     *v++ = COPY(*av);
  119.     *v = NULL;
  120. }
  121.  
  122.  
  123. /*
  124. **  Add <> around Message-ID if needed.
  125. */
  126. STATIC STRING
  127. CCgetid(p, store)
  128.     char        *p;
  129.     char        **store;
  130. {
  131.     static char        NULLMESGID[] = "1 Empty Message-ID";
  132.     static BUFFER    Save;
  133.     int            i;
  134.  
  135.     if (*p == '\0')
  136.     return NULLMESGID;
  137.     if (*p == '<') {
  138.     if (p[1] == '\0' || p[1] == '>')
  139.         return NULLMESGID;
  140.     *store = p;
  141.     return NULL;
  142.     }
  143.  
  144.     /* Make sure the Message-ID buffer has room. */
  145.     i = 1 + strlen(p) + 1 + 1;
  146.     if (Save.Data == NULL) {
  147.     Save.Size = i;
  148.     Save.Data = NEW(char, Save.Size);
  149.     }
  150.     else if (Save.Size < i) {
  151.     Save.Size = i;
  152.     RENEW(Save.Data, char, Save.Size);
  153.     }
  154.     *store = Save.Data;
  155.     (void)sprintf(*store, "<%s>", p);
  156.     return NULL;
  157. }
  158.  
  159.  
  160. /*
  161. **  Abort and dump core.
  162. */
  163. STATIC STRING
  164. CCxabort(av)
  165.     char        *av[];
  166. {
  167.     syslog(L_FATAL, "%s abort %s", LogName, av[0]);
  168.     abort();
  169.     syslog(L_FATAL, "%s cant abort %m", LogName);
  170.     CleanupAndExit(1, av[0]);
  171.     /* NOTREACHED */
  172. }
  173.  
  174.  
  175. /*
  176. **  Do the work needed to add a history entry.
  177. */
  178. STATIC STRING
  179. CCaddhist(av)
  180.     char        *av[];
  181. {
  182.     static char        DIGITS[] = "0123456789";
  183.     ARTDATA        Data;
  184.     STRING        p;
  185.     BOOL        ok;
  186.  
  187.     /* Check the fields. */
  188.     if ((p = CCgetid(av[0], &Data.MessageID)) != NULL)
  189.     return p;
  190.     if (HIShavearticle(Data.MessageID))
  191.     return "1 Duplicate";
  192.     if (strspn(av[1], DIGITS) != strlen(av[1]))
  193.     return "1 Bad arrival date";
  194.     Data.Arrived = atol(av[1]);
  195.     if (strspn(av[2], DIGITS) != strlen(av[2]))
  196.     return "1 Bad expiration date";
  197.     Data.Expires = atol(av[2]);
  198.     if (strspn(av[3], DIGITS) != strlen(av[3]))
  199.     return "1 Bad posted date";
  200.     Data.Posted = atol(av[3]);
  201.  
  202.     if (Mode == OMrunning)
  203.     ok = HISwrite(&Data, av[4]);
  204.     else {
  205.     /* Possible race condition, but documented in ctlinnd manpage. */
  206.     HISsetup();
  207.     ok = HISwrite(&Data, av[4]);
  208.     HISclose();
  209.     }
  210.     return ok ? NULL : "1 Write failed";
  211. }
  212.  
  213.  
  214. /*
  215. **  Do the work to allow foreign connectiosn.
  216. */
  217. STATIC STRING
  218. CCallow(av)
  219.     char    *av[];
  220. {
  221.     char    *p;
  222.  
  223.     if (RejectReason == NULL)
  224.     return "1 Already allowed";
  225.     p = av[0];
  226.     if (*p && !EQ(p, RejectReason))
  227.     return "1 Wrong reason";
  228.     DISPOSE(RejectReason);
  229.     RejectReason = NULL;
  230.     return NULL;
  231. }
  232.  
  233.  
  234. /*
  235. **  Do the work needed to start feeding a (new) site.
  236. */
  237. STATIC STRING
  238. CCbegin(av)
  239.     char        *av[];
  240. {
  241.     SITE        *sp;
  242.     register int    i;
  243.     register int    length;
  244.     register STRING    p;
  245.     register char    **strings;
  246.     register NEWSGROUP    *ngp;
  247.     STRING        error;
  248.     char        *subbed;
  249.  
  250.     /* If site already exists, drop it. */
  251.     if (SITEfind(av[0]) != NULL && (p = CCdrop(av)) != NULL)
  252.     return p;
  253.  
  254.     /* Find the named site. */
  255.     length = strlen(av[0]);
  256.     for (strings = SITEreadfile(TRUE), i = 0; (p = strings[i]) != NULL; i++)
  257.     if ((p[length] == NF_FIELD_SEP || p[length] == NF_SUBFIELD_SEP)
  258.      && caseEQn(p, av[0], length)) {
  259.         p = COPY(p);
  260.         break;
  261.     }
  262.     if (p == NULL)
  263.     return CCnosite;
  264.  
  265.     if (p[0] == 'M' && p[1] == 'E' && p[2] == NF_FIELD_SEP)
  266.     sp = &ME;
  267.     else {
  268.     /* Get space for the new site entry, and space for it in all
  269.      * the groups. */
  270.     for (i = nSites, sp = Sites; --i >= 0; sp++)
  271.         if (sp->Name == NULL)
  272.         break;
  273.     if (i < 0) {
  274.         nSites++;
  275.         RENEW(Sites, SITE, nSites);
  276.         sp = &Sites[nSites - 1];
  277.         for (i = nGroups, ngp = Groups; --i >= 0; ngp++)
  278.         RENEW(ngp->Sites, int, nSites);
  279.     }
  280.     SITElinkall();
  281.     }
  282.  
  283.     /* Parse. */
  284.     subbed = NEW(char, nGroups);
  285.     error = SITEparseone(p, sp, subbed);
  286.     DISPOSE(subbed);
  287.     if (error != NULL) {
  288.     DISPOSE(p);
  289.     syslog(L_ERROR, "%s bad_newsfeeds %s", av[0], error);
  290.     return "1 Parse error";
  291.     }
  292.  
  293.     if (sp != &ME && (!SITEsetup(sp) || !SITEfunnelpatch()))
  294.     return "1 Startup error";
  295.     SITEforward(sp, "begin");
  296.     return NULL;
  297. }
  298.  
  299.  
  300. /*
  301. **  Common code to change a group's flags.
  302. */
  303. STATIC STRING
  304. CCdochange(ngp, Rest)
  305.     register NEWSGROUP    *ngp;
  306.     char        *Rest;
  307. {
  308.     int            length;
  309.     char        *p;
  310.  
  311.     if (ngp->Rest[0] == Rest[0]) {
  312.     length = strlen(Rest);
  313.     if (ngp->Rest[length] == '\n' && EQn(ngp->Rest, Rest, length))
  314.         return "0 Group status unchanged";
  315.     }
  316.     if (Mode != OMrunning)
  317.     return CCnotrunning;
  318.  
  319.     p = COPY(ngp->Name);
  320.     if (!ICDchangegroup(ngp, Rest)) {
  321.     syslog(L_NOTICE, "%s cant change_group %s to %s", LogName, p, Rest);
  322.     DISPOSE(p);
  323.     return "1 Change failed (probably can't write active?)";
  324.     }
  325.     syslog(L_NOTICE, "%s change_group %s to %s", LogName, p, Rest);
  326.     DISPOSE(p);
  327.     return NULL;
  328. }
  329.  
  330.  
  331. /*
  332. **  Change the mode of a newsgroup.
  333. */
  334. STATIC STRING
  335. CCchgroup(av)
  336.     char    *av[];
  337. {
  338.     NEWSGROUP    *ngp;
  339.     char    *Rest;
  340.  
  341.     if ((ngp = NGfind(av[0])) == NULL)
  342.     return CCnogroup;
  343.     Rest = av[1];
  344.     if (Rest[0] != NF_FLAG_ALIAS) {
  345.     Rest[1] = '\0';
  346.     if (CTYPE(isupper, Rest[0]))
  347.         Rest[0] = tolower(Rest[0]);
  348.     }
  349.     return CCdochange(ngp, Rest);
  350. }
  351.  
  352.  
  353. /*
  354. **  Cancel a message.
  355. */
  356. STRING
  357. CCcancel(av)
  358.     char    *av[];
  359. {
  360.     ARTDATA    Data;
  361.     STRING    p;
  362.  
  363.     Data.Posted = Now.time;
  364.     Data.Expires = 0;
  365.     Data.Feedsite = "?";
  366.     if ((p = CCgetid(av[0], &Data.MessageID)) != NULL)
  367.     return p;
  368.     if (Mode == OMrunning)
  369.     ARTcancel(&Data, Data.MessageID, TRUE);
  370.     else {
  371.     /* Possible race condition, but documented in ctlinnd manpage. */
  372.     HISsetup();
  373.     ARTcancel(&Data, Data.MessageID, TRUE);
  374.     HISclose();
  375.     }
  376. #if    defined(DO_LOG_CANCEL_COMMANDS)
  377.     syslog(L_NOTICE, "%s cancelled %s", LogName, Data.MessageID);
  378. #endif    /* defined(DO_LOG_CANCEL_COMMANDS) */
  379.     return NULL;
  380. }
  381.  
  382.  
  383. /*
  384. **  Syntax-check the newsfeeds file.
  385. */
  386. /* ARGSUSED */
  387. STRING
  388. CCcheckfile(av)
  389.     char        *av[];
  390. {
  391.     register char    **strings;
  392.     register char    *p;
  393.     register int    i;
  394.     register int    errors;
  395.     STRING        error;
  396.     SITE        fake;
  397.  
  398.     /* Parse all site entries. */
  399.     strings = SITEreadfile(FALSE);
  400.     fake.Buffer.Size = 0;
  401.     fake.Buffer.Data = NULL;
  402.     for (errors = 0, i = 0; (p = strings[i]) != NULL; i++) {
  403.     if ((error = SITEparseone(p, &fake, (char *)NULL)) != NULL) {
  404.         syslog(L_ERROR, "%s bad_newsfeeds %s", MaxLength(p, p), error);
  405.         errors++;
  406.     }
  407.     SITEfree(&fake);
  408.     }
  409.     DISPOSE(strings);
  410.  
  411.     if (errors == 0)
  412.     return NULL;
  413.  
  414.     (void)sprintf(CCreply.Data, "1 Found %d errors -- see syslog", errors);
  415.     return CCreply.Data;
  416. }
  417.  
  418.  
  419. /*
  420. **  Drop a site.
  421. */
  422. STATIC STRING
  423. CCdrop(av)
  424.     char        *av[];
  425. {
  426.     SITE        *sp;
  427.     register NEWSGROUP    *ngp;
  428.     register int    *ip;
  429.     register int    idx;
  430.     register int    i;
  431.     register int    j;
  432.  
  433.     if ((sp = SITEfind(av[0])) == NULL)
  434.     return CCnosite;
  435.  
  436.     SITEdrop(sp);
  437.  
  438.     /* Loop over all groups, and if the site is in a group, clobber it. */
  439.     for (idx = sp - Sites, i = nGroups, ngp = Groups; --i >= 0; ngp++)
  440.     for (j = ngp->nSites, ip = ngp->Sites; --j >= 0; ip++)
  441.         if (*ip == idx)
  442.         *ip = NOSITE;
  443.  
  444.     return NULL;
  445. }
  446.  
  447.  
  448. /*
  449. **  Flush all sites or one site.
  450. */
  451. STATIC STRING
  452. CCflush(av)
  453.     char        *av[];
  454. {
  455.     register SITE    *sp;
  456.     register int    i;
  457.     register char    *p;
  458.  
  459.     p = av[0];
  460.     if (*p == '\0') {
  461.     ICDwrite();
  462.     for (sp = Sites, i = nSites; --i >= 0; sp++)
  463.         SITEflush(sp, TRUE);
  464.     syslog(L_NOTICE, "%s flush_all", LogName);
  465.     }
  466.     else  {
  467.     if ((sp = SITEfind(p)) == NULL)
  468.         return CCnosite;
  469.     syslog(L_NOTICE, "%s flush", sp->Name);
  470.     SITEflush(sp, TRUE);
  471.     }
  472.     return NULL;
  473. }
  474.  
  475.  
  476. /*
  477. **  Flush the log files.
  478. */
  479. /* ARGSUSED0 */
  480. STATIC STRING
  481. CCflushlogs(av)
  482.     char    *av[];
  483. {
  484.     if (Debug)
  485.     return "1 In debug mode";
  486.  
  487.     ICDwrite();
  488.     ReopenLog(Log);
  489.     ReopenLog(Errlog);
  490.     return NULL;
  491. }
  492.  
  493.  
  494. /*
  495. **  Leave paused or throttled mode.
  496. */
  497. STATIC STRING
  498. CCgo(av)
  499.     char    *av[];
  500. {
  501.     static char    YES[] = "y";
  502.     char    *p;
  503.  
  504.     p = av[0];
  505.     if (Reservation && EQ(p, Reservation)) {
  506.     DISPOSE(Reservation);
  507.     Reservation = NULL;
  508.     }
  509.     if (RejectReason && EQ(p, RejectReason)) {
  510.     DISPOSE(RejectReason);
  511.     RejectReason = NULL;
  512.     }
  513.  
  514.     if (Mode == OMrunning)
  515.     return "1 Already running";
  516.     if (*p && !EQ(p, ModeReason))
  517.     return "1 Wrong reason";
  518.     DISPOSE(ModeReason);
  519.     ModeReason = NULL;
  520.     Mode = OMrunning;
  521.  
  522.     if (NNRPReason && NNRPFollows) {
  523.     av[0] = YES;
  524.     av[1] = p;
  525.     (void)CCreaders(av);
  526.     }
  527.     if (ErrorCount < 0)
  528.     ErrorCount = IO_ERROR_COUNT;
  529.     HISsetup();
  530.     syslog(L_NOTICE, "%s running", LogName);
  531.     if (ICDneedsetup)
  532.     ICDsetup(TRUE);
  533.     SCHANwakeup((POINTER)&Mode);
  534.     return NULL;
  535. }
  536.  
  537.  
  538. /*
  539. **  Hangup a channel.
  540. */
  541. STATIC STRING
  542. CChangup(av)
  543.     char        *av[];
  544. {
  545.     register CHANNEL    *cp;
  546.     register int    fd;
  547.     register char    *p;
  548.     int            i;
  549.  
  550.     /* Parse the argument, a channel number. */
  551.     for (p = av[0], fd = 0; *p; p++) {
  552.     if (!CTYPE(isdigit, *p))
  553.         return "1 Bad channel number";
  554.     fd = fd * 10 + *p - '0';
  555.     }
  556.  
  557.     /* Loop over all channels for the desired one. */
  558.     for (i = 0; (cp = CHANiter(&i, CTany)) != NULL; )
  559.     if (cp->fd == fd) {
  560.         p = CHANname(cp);
  561.         switch (cp->Type) {
  562.         default:
  563.         (void)sprintf(CCreply.Data, "1 Can't close %s", p);
  564.         return CCreply.Data;
  565.         case CTexploder:
  566.         case CTprocess:
  567.         case CTfile:
  568.         case CTnntp:
  569.         syslog(L_NOTICE, "%s hangup", p);
  570.         CHANclose(cp, p);
  571.         return NULL;
  572.         }
  573.     }
  574.     return "1 Not active";
  575. }
  576.  
  577.  
  578. /*
  579. **  Return our operating mode.
  580. */
  581. /* ARGSUSED */
  582. STATIC STRING
  583. CCmode(av)
  584.     char        *av[];
  585. {
  586.     register char    *p;
  587.     register int    i;
  588.     int            h;
  589.     char        buff[BUFSIZ];
  590.  
  591.     p = buff;
  592.     p += strlen(strcpy(buff, "0 Server "));
  593.  
  594.     /* Server's mode. */
  595.     switch (Mode) {
  596.     default:
  597.     (void)sprintf(p, "Unknown %d", Mode);
  598.     p += strlen(p);
  599.     break;
  600.     case OMrunning:
  601.     p += strlen(strcpy(p, "running"));
  602.     break;
  603.     case OMpaused:
  604.     p += strlen(strcpy(p, "paused "));
  605.     p += strlen(strcpy(p, ModeReason));
  606.     break;
  607.     case OMthrottled:
  608.     p += strlen(strcpy(p, "throttled "));
  609.     p += strlen(strcpy(p, ModeReason));
  610.     break;
  611.     }
  612.     *p++ = '\n';
  613.     if (RejectReason) {
  614.     p += strlen(strcpy(p, "Rejecting "));
  615.     p += strlen(strcpy(p, RejectReason));
  616.     }
  617.     else
  618.     p += strlen(strcpy(p, "Allowing remote connections"));
  619.  
  620.     /* Server parameters. */
  621.     for (i = 0, h = 0; CHANiter(&h, CTnntp) != NULL; )
  622.     i++;
  623.     *p++ = '\n';
  624.     (void)sprintf(p, "Parameters c %ld i %d (%d) l %ld o %d t %ld %s %s",
  625.         (long)Cutoff / (24L * 60L * 60L),
  626.         MaxIncoming, i,
  627.         LargestArticle, MaxOutgoing, (long)TimeOut.tv_sec,
  628.         AmSlave ? "slave" : "normal",
  629.         AnyIncoming ? "any" : "specified");
  630.     p += strlen(p);
  631.  
  632.     /* Reservation. */
  633.     *p++ = '\n';
  634.     if (Reservation) {
  635.     (void)sprintf(p, "Reserved %s", Reservation);
  636.     p += strlen(p);
  637.     }
  638.     else
  639.     p += strlen(strcpy(p, "Not reserved"));
  640.  
  641.     /* Newsreaders. */
  642.     *p++ = '\n';
  643.     p += strlen(strcpy(p, "Readers "));
  644.     if (NNRPFollows)
  645.     p += strlen(strcpy(p, "follow "));
  646.     else
  647.     p += strlen(strcpy(p, "separate "));
  648.     if (NNRPReason == NULL)
  649.     p += strlen(strcpy(p, "enabled"));
  650.     else {
  651.     (void)sprintf(p, "disabled %s", NNRPReason);
  652.     p += strlen(p);
  653.     }
  654.     
  655.     i = strlen(buff);
  656.     if (CCreply.Size <= i) {
  657.     CCreply.Size = i;
  658.     RENEW(CCreply.Data, char, CCreply.Size + 1);
  659.     }
  660.     (void)strcpy(CCreply.Data, buff);
  661.     return CCreply.Data;
  662. }
  663.  
  664.  
  665. /*
  666. **  Name the channels.  ("Name the bats -- simple names.")
  667. */
  668. STATIC STRING
  669. CCname(av)
  670.     char        *av[];
  671. {
  672.     static char        NL[] = "\n";
  673.     static char        NIL[] = "\0";
  674.     register CHANNEL    *cp;
  675.     register char    *p;
  676.     register int    count;
  677.     int            i;
  678.  
  679.     p = av[0];
  680.     if (*p != '\0') {
  681.     if ((cp = CHANfromdescriptor(atoi(p))) == NULL)
  682.         return COPY(CCnochannel);
  683.     (void)sprintf(CCreply.Data, "0 %s", CHANname(cp));
  684.     return CCreply.Data;
  685.     }
  686.     BUFFset(&CCreply, "0 ", 2);
  687.     for (count = 0, i = 0; (cp = CHANiter(&i, CTany)) != NULL; ) {
  688.     if (cp->Type == CTfree)
  689.         continue;
  690.     if (++count > 1)
  691.         BUFFappend(&CCreply, NL, 1);
  692.     p = CHANname(cp);
  693.     BUFFappend(&CCreply, p, strlen(p));
  694.     }
  695.     BUFFappend(&CCreply, NIL, 1);
  696.     return CCreply.Data;
  697. }
  698.  
  699.  
  700. /*
  701. **  Create a newsgroup.
  702. */
  703. STATIC STRING
  704. CCnewgroup(av)
  705.     char        *av[];
  706. {
  707.     static char        TIMES[] = _PATH_ACTIVETIMES;
  708.     static char        WHEN[] = "updating active.times";
  709.     register int    fd;
  710.     register char    *p;
  711.     NEWSGROUP        *ngp;
  712.     char        *Name;
  713.     char        *Rest;
  714.     STRING        who;
  715.     char        buff[SMBUF];
  716.  
  717.     Name = av[0];
  718.     if (Name[0] == '.' || strspn(Name, "0123456789") == strlen(Name))
  719.     return "1 Illegal newsgroup name";
  720.     for (p = Name; *p; p++)
  721.     if (*p == '.') {
  722.         if (p[1] == '.' || p[1] == '\0')
  723.         return "1 Double or trailing period in newsgroup name";
  724.     }
  725.     else if (ISWHITE(*p) || *p == ':' || *p == '!')
  726.         return "1 Illegal character in newsgroup name";
  727.  
  728.     Rest = av[1];
  729.     if (Rest[0] != NF_FLAG_ALIAS) {
  730.     Rest[1] = '\0';
  731.     if (CTYPE(isupper, Rest[0]))
  732.         Rest[0] = tolower(Rest[0]);
  733.     }
  734.     if ((ngp = NGfind(Name)) != NULL)
  735.     return CCdochange(ngp, Rest);
  736.  
  737.     /* Update the log of groups created.  Don't use stdio because SunOS
  738.      * 4.1 has broken libc which can't handle fd's greater than 127. */
  739.     if ((fd = open(TIMES, O_WRONLY | O_APPEND | O_CREAT, 0664)) < 0) {
  740.     IOError(WHEN);
  741.     syslog(L_ERROR, "%s cant fopen %s %m", LogName, TIMES);
  742.     }
  743.     else {
  744.     who = av[2];
  745.     if (*who == '\0')
  746.         who = NEWSMASTER;
  747.     (void)sprintf(buff, "%s %ld %s\n", Name, Now.time, who);
  748.     if (xwrite(fd, buff, strlen(buff)) < 0) {
  749.         IOError(WHEN);
  750.         syslog(L_ERROR, "%s cant write %s %m", LogName, TIMES);
  751.     }
  752.     if (close(fd) < 0) {
  753.         IOError(WHEN);
  754.         syslog(L_ERROR, "%s cant close %s %m", LogName, TIMES);
  755.     }
  756.     if (AmRoot)
  757.         xchown(TIMES);
  758.     }
  759.  
  760.     /* Update the in-core data. */
  761.     if (!ICDnewgroup(Name, Rest))
  762.     return "1 Failed";
  763.     syslog(L_NOTICE, "%s newgroup %s as %s", LogName, Name, Rest);
  764.  
  765.     if (*Rest != NF_FLAG_ALIAS) {
  766.     /* Create the spool directory. */
  767.     for (p = Name; *p; p++)
  768.         if (*p == '.')
  769.         *p = '/';
  770.     if (!MakeSpoolDirectory(Name))
  771.         syslog(L_NOTICE, "%s cant mkdir %s %m", LogName, Name);
  772.     }
  773.     return NULL;
  774. }
  775.  
  776.  
  777. /*
  778. **  Parse and set a boolean flag.
  779. */
  780. STATIC BOOL
  781. CCparsebool(name, bp, value)
  782.     char    name;
  783.     BOOL    *bp;
  784.     char    value;
  785. {
  786.     switch (value) {
  787.     default:
  788.     return FALSE;
  789.     case 'y':
  790.     *bp = FALSE;
  791.     break;
  792.     case 'n':
  793.     *bp = TRUE;
  794.     break;
  795.     }
  796.     syslog(L_NOTICE, "%s changed -%c %c", LogName, name, value);
  797.     return TRUE;
  798. }
  799.  
  800.  
  801. /*
  802. **  Change a running parameter.
  803. */
  804. STATIC STRING
  805. CCparam(av)
  806.     char    *av[];
  807. {
  808.     static char    BADVAL[] = "1 Bad value";
  809.     char    *p;
  810.  
  811.     p = av[1];
  812.     switch (av[0][0]) {
  813.     default:
  814.     return "1 Unknown parameter";
  815.     case 'a':
  816.     if (!CCparsebool('a', &AnyIncoming, *p))
  817.         return BADVAL;
  818.     break;
  819.     case 'c':
  820.     Cutoff = atoi(p) * 24 * 60 * 60;
  821.     syslog(L_NOTICE, "%s changed -c %d", LogName, Cutoff);
  822.     break;
  823.     case 'i':
  824.     MaxIncoming = atoi(p);
  825.     syslog(L_NOTICE, "%s changed -i %d", LogName, MaxIncoming);
  826.     break;
  827.     case 'l':
  828.     LargestArticle = atol(p);
  829.     syslog(L_NOTICE, "%s changed -l %ld", LogName, LargestArticle);
  830.     break;
  831.     case 'n':
  832.     if (!CCparsebool('n', &NNRPFollows, *p))
  833.         return BADVAL;
  834.     break;
  835.     case 'o':
  836.     MaxOutgoing = atoi(p);
  837.     syslog(L_NOTICE, "%s changed -o %d", LogName, MaxOutgoing);
  838.     break;
  839.     case 't':
  840.     TimeOut.tv_sec = atol(p);
  841.     syslog(L_NOTICE, "%s changed -t %ld", LogName, (long)TimeOut.tv_sec);
  842.     break;
  843.     }
  844.     return NULL;
  845. }
  846.  
  847.  
  848. /*
  849. **  Common code to implement a pause or throttle.
  850. */
  851. STRING
  852. CCblock(NewMode, reason)
  853.     OPERATINGMODE    NewMode;
  854.     char        *reason;
  855. {
  856.     static char        NO[] = "n";
  857.     STRING        av[2];
  858.  
  859.     if (*reason == '\0')
  860.     return CCnoreason;
  861.  
  862.     if (Reservation) {
  863.     if (!EQ(reason, Reservation)) {
  864.         (void)sprintf(CCreply.Data, "1 Reserved \"%s\"", Reservation);
  865.         return CCreply.Data;
  866.     }
  867.     DISPOSE(Reservation);
  868.     Reservation = NULL;
  869.     }
  870.     ICDwrite();
  871.     HISclose();
  872.     Mode = NewMode;
  873.     if (ModeReason)
  874.     DISPOSE(ModeReason);
  875.     ModeReason = COPY(reason);
  876.     if (NNRPReason == NULL && NNRPFollows) {
  877.     av[0] = NO;
  878.     av[1] = ModeReason;
  879.     (void)CCreaders(av);
  880.     }
  881.     syslog(L_NOTICE, "%s %s %s",
  882.     LogName, NewMode == OMpaused ? "paused" : "throttled", reason);
  883.     return NULL;
  884. }
  885.  
  886.  
  887. /*
  888. **  Enter paused mode.
  889. */
  890. STATIC STRING
  891. CCpause(av)
  892.     char    *av[];
  893. {
  894.     switch (Mode) {
  895.     case OMrunning:
  896.     return CCblock(OMpaused, av[0]);
  897.     case OMpaused:
  898.     return "1 Already paused";
  899.     case OMthrottled:
  900.     return "1 Already throttled";
  901.     }
  902.     return "1 Unknown mode";
  903. }
  904.  
  905.  
  906. /*
  907. **  Allow or disallow newsreaders.
  908. */
  909. STATIC STRING
  910. CCreaders(av)
  911.     char    *av[];
  912. {
  913.     char    *p;
  914.  
  915.     switch (av[0][0]) {
  916.     default:
  917.     return "1 Bad flag";
  918.     case 'y':
  919.     if (NNRPReason == NULL)
  920.         return "1 Already allowing readers";
  921.     p = av[1];
  922.     if (*p && !EQ(p, NNRPReason))
  923.         return "1 Wrong reason";
  924.     DISPOSE(NNRPReason);
  925.     NNRPReason = NULL;
  926.     break;
  927.     case 'n':
  928.     if (NNRPReason)
  929.         return "1 Already not allowing readers";
  930.     p = av[1];
  931.     if (*p == '\0')
  932.         return CCnoreason;
  933.     NNRPReason = COPY(p);
  934.     break;
  935.     }
  936.     return NULL;
  937. }
  938.  
  939.  
  940. /*
  941. **  Re-exec ourselves.
  942. */
  943. STATIC STRING
  944. CCxexec(av)
  945.     char    *av[];
  946. {
  947.     static char    INND[] = _PATH_INND;
  948.     static char    INNDSTART[] = _PATH_INNDSTART;
  949.     char    *p;
  950.  
  951.     if (CCargv == NULL)
  952.     return "1 no argv!";
  953.     
  954.     /* Get the pathname. */
  955.     p = av[0];
  956.     if (*p == '\0')
  957.     CCargv[0] = AmRoot ? INND : INNDSTART;
  958.     else if (EQ(p, "innd"))
  959.     CCargv[0] = INND;
  960.     else if (EQ(p, "inndstart"))
  961.     CCargv[0] = INNDSTART;
  962.     else
  963.     return "1 Bad value";
  964.  
  965.     JustCleanup();
  966.     syslog(L_FATAL, "%s execv %s", LogName, CCargv[0]);
  967.     (void)execv(CCargv[0], CCargv);
  968.     syslog(L_FATAL, "%s cant execv %s %m", LogName, CCargv[0]);
  969.     _exit(1);
  970.     /* NOTREACHED */
  971. }
  972.  
  973.  
  974. /*
  975. **  Refile an article.
  976. */
  977. STATIC STRING
  978. CCrefile(av)
  979.     char    *av[];
  980. {
  981.     char    *head;
  982.  
  983.     /* xxx multiple groups? */
  984.     if (NGfind(av[1]) == NULL)
  985.     return CCnogroup;
  986.  
  987.     head = ARTreadheader(av[0]);
  988.     if (head == NULL)
  989.     return "1 No such article";
  990.  
  991.     return "1 Not yet implemented";
  992. }
  993.  
  994.  
  995. /*
  996. **  Reject remote readers.
  997. */
  998. STATIC STRING
  999. CCreject(av)
  1000.     char    *av[];
  1001. {
  1002.     if (RejectReason)
  1003.     return "1 Already rejecting";
  1004.     RejectReason = COPY(av[0]);
  1005.     return NULL;
  1006. }
  1007.  
  1008.  
  1009. /*
  1010. **  Re-read all in-core data.
  1011. */
  1012. STATIC STRING
  1013. CCreload(av)
  1014.     char    *av[];
  1015. {
  1016.     static char    BADSCHEMA[] = "1 Can't read schema";
  1017.     STRING    p;
  1018.  
  1019.     p = av[0];
  1020.     if (*p == '\0' || EQ(p, "all")) {
  1021.     SITEflushall(FALSE);
  1022.     HISclose();
  1023.     RCreadlist();
  1024.     HISsetup();
  1025.     ICDwrite();
  1026.     ICDsetup(TRUE);
  1027.     if (!ARTreadschema())
  1028.         return BADSCHEMA;
  1029.     p = "all";
  1030.     }
  1031.     else if (EQ(p, "active") || EQ(p, "newsfeeds")) {
  1032.     SITEflushall(FALSE);
  1033.     ICDwrite();
  1034.     ICDsetup(TRUE);
  1035.     }
  1036.     else if (EQ(p, "history")) {
  1037.     HISclose();
  1038.     HISsetup();
  1039.     }
  1040.     else if (EQ(p, "hosts.nntp"))
  1041.     RCreadlist();
  1042.     else if (EQ(p, "overview.fmt")) {
  1043.     if (!ARTreadschema())
  1044.         return BADSCHEMA;
  1045.     }
  1046.     else
  1047.     return "1 Unknown reload type";
  1048.  
  1049.     syslog(L_NOTICE, "%s reload %s %s", LogName, p, av[1]);
  1050.     return NULL;
  1051. }
  1052.  
  1053.  
  1054. /*
  1055. **  Renumber the active file.
  1056. */
  1057. STATIC STRING
  1058. CCrenumber(av)
  1059.     char    *av[];
  1060. {
  1061.     char    *p;
  1062.     NEWSGROUP    *ngp;
  1063.  
  1064.     if (Mode != OMrunning)
  1065.     return CCnotrunning;
  1066.     if (ICDneedsetup)
  1067.     return "1 Must first reload newsfeeds";
  1068.     p = av[0];
  1069.     if (*p) {
  1070.     if ((ngp = NGfind(p)) == NULL)
  1071.         return CCnogroup;
  1072.     if (!NGrenumber(ngp))
  1073.         return "1 Failed (see syslog)";
  1074.     }
  1075.     else
  1076.     ICDrenumberactive();
  1077.     return NULL;
  1078. }
  1079.  
  1080.  
  1081. /*
  1082. **  Reserve a lock.
  1083. */
  1084. STATIC STRING
  1085. CCreserve(av)
  1086.     char    *av[];
  1087. {
  1088.     char    *p;
  1089.  
  1090.     if (Mode != OMrunning)
  1091.     return CCnotrunning;
  1092.     p = av[0];
  1093.     if (*p) {
  1094.     /* Trying to make a reservation. */
  1095.     if (Reservation)
  1096.         return "1 Already reserved";
  1097.     Reservation = COPY(p);
  1098.     }
  1099.     else {
  1100.     /* Trying to remove a reservation. */
  1101.     if (Reservation == NULL)
  1102.         return "1 Not reserved";
  1103.     DISPOSE(Reservation);
  1104.     Reservation = NULL;
  1105.     }
  1106.     return NULL;
  1107. }
  1108.  
  1109.  
  1110. /*
  1111. **  Remove a newsgroup.
  1112. */
  1113. STATIC STRING
  1114. CCrmgroup(av)
  1115.     char    *av[];
  1116. {
  1117.     NEWSGROUP    *ngp;
  1118.  
  1119.     if ((ngp = NGfind(av[0])) == NULL)
  1120.     return CCnogroup;
  1121.  
  1122.     /* Update the in-core data. */
  1123.     if (!ICDrmgroup(ngp))
  1124.     return "1 Failed";
  1125.     syslog(L_NOTICE, "%s rmgroup %s", LogName, av[0]);
  1126.     return NULL;
  1127. }
  1128.  
  1129.  
  1130. /*
  1131. **  Send a command line to an exploder.
  1132. */
  1133. STATIC STRING
  1134. CCsend(av)
  1135.     char        *av[];
  1136. {
  1137.     SITE        *sp;
  1138.  
  1139.     if ((sp = SITEfind(av[0])) == NULL)
  1140.     return CCnosite;
  1141.     if (sp->Type != FTexploder)
  1142.     return CCwrongtype;
  1143.     SITEwrite(sp, av[1]);
  1144.     return NULL;
  1145. }
  1146.  
  1147.  
  1148. /*
  1149. **  Shut down the system.
  1150. */
  1151. STATIC STRING
  1152. CCshutdown(av)
  1153.     char    *av[];
  1154. {
  1155.     syslog(L_NOTICE, "%s shutdown %s", LogName, av[0]);
  1156.     CleanupAndExit(0, av[0]);
  1157.     /* NOTREACHED */
  1158. }
  1159.  
  1160.  
  1161. /*
  1162. **  Send a signal to a site's feed.
  1163. */
  1164. STATIC STRING
  1165. CCsignal(av)
  1166.     char    *av[];
  1167. {
  1168.     register SITE    *sp;
  1169.     register char    *p;
  1170.     int            s;
  1171.     int            oerrno;
  1172.  
  1173.     /* Parse the signal. */
  1174.     p = av[0];
  1175.     if (*p == '-')
  1176.     p++;
  1177.     if (caseEQ(p, "HUP"))
  1178.     s = SIGHUP;
  1179.     else if (caseEQ(p, "INT"))
  1180.     s = SIGINT;
  1181.     else if (caseEQ(p, "TERM"))
  1182.     s = SIGTERM;
  1183.     else if ((s = atoi(p)) <= 0)
  1184.     return "1 Invalid signal";
  1185.  
  1186.     /* Parse the site. */
  1187.     p = av[1];
  1188.     if ((sp = SITEfind(p)) == NULL)
  1189.     return CCnosite;
  1190.     if (sp->Type != FTchannel && sp->Type != FTexploder)
  1191.     return CCwrongtype;
  1192.     if (sp->Spooling || sp->Process  < 0)
  1193.     return "1 Site has no process";
  1194.  
  1195.     /* Do it. */
  1196.     if (kill(sp->pid, s) < 0) {
  1197.     oerrno = errno;
  1198.     syslog(L_ERROR, "%s cant kill %d %d site %s, %m", sp->Process, s, p);
  1199.     (void)sprintf(CCreply.Data, "1 Can't signal process %d, %s",
  1200.         sp->Process, strerror(oerrno));
  1201.     return CCreply.Data;
  1202.     }
  1203.  
  1204.     return NULL;
  1205. }
  1206.  
  1207.  
  1208. /*
  1209. **  Enter throttled mode.
  1210. */
  1211. STATIC STRING
  1212. CCthrottle(av)
  1213.     char    *av[];
  1214. {
  1215.     char    *p;
  1216.  
  1217.     p = av[0];
  1218.     switch (Mode) {
  1219.     case OMpaused:
  1220.     if (*p && !EQ(p, ModeReason))
  1221.         return "1 Already paused";
  1222.     /* FALLTHROUGH */
  1223.     case OMrunning:
  1224.     return CCblock(OMthrottled, p);
  1225.     case OMthrottled:
  1226.     return "1 Already throttled";
  1227.     }
  1228.     return "1 unknown mode";
  1229. }
  1230.  
  1231.  
  1232. /*
  1233. **  Add or remove tracing.
  1234. */
  1235. STATIC STRING
  1236. CCtrace(av)
  1237.     char    *av[];
  1238. {
  1239.     char    *p;
  1240.     BOOL    Flag;
  1241.     STRING    word;
  1242.     CHANNEL    *cp;
  1243.  
  1244.     /* Parse the flag. */
  1245.     p = av[1];
  1246.     switch (p[0]) {
  1247.     default:            return "1 Bad trace flag";
  1248.     case 'y': case 'Y':        Flag = TRUE;    word = "on";    break;
  1249.     case 'n': case 'N':        Flag = FALSE;    word = "off";    break;
  1250.     }
  1251.  
  1252.     /* Parse what's being traced. */
  1253.     p = av[0];
  1254.     switch (*p) {
  1255.     default:
  1256.     return "1 Bad trace item";
  1257.     case 'i': case 'I':
  1258.     Tracing = Flag;
  1259.     syslog(L_NOTICE, "%s trace innd %s", LogName, word);
  1260.     break;
  1261.     case 'n': case 'N':
  1262.     NNRPTracing = Flag;
  1263.     syslog(L_NOTICE, "%s trace nnrpd %s", LogName, word);
  1264.     break;
  1265.     case '0': case '1': case '2': case '3': case '4':
  1266.     case '5': case '6': case '7': case '8': case '9':
  1267.     if ((cp = CHANfromdescriptor(atoi(p))) == NULL)
  1268.         return CCnochannel;
  1269.     CHANtracing(cp, Flag);
  1270.     break;
  1271.     }
  1272.     return NULL;
  1273. }
  1274.  
  1275.  
  1276.  
  1277. /*
  1278. **  Split up the text into fields and stuff them in argv.  Return the
  1279. **  number of elements or -1 on error.
  1280. */
  1281. STATIC int
  1282. CCargsplit(p, end, argv, size)
  1283.     register char    *p;
  1284.     register char    *end;
  1285.     register char    **argv;
  1286.     register int    size;
  1287. {
  1288.     char        **save;
  1289.  
  1290.     for (save = argv, *argv++ = p, size--; p < end; p++)
  1291.     if (*p == SC_SEP) {
  1292.         if (--size <= 0)
  1293.         return -1;
  1294.         *p = '\0';
  1295.         *argv++ = p + 1;
  1296.     }
  1297.     *argv = NULL;
  1298.     return argv - save;
  1299. }
  1300.  
  1301.  
  1302. /*
  1303. **  Read function.  Read and process the message.
  1304. */
  1305. STATIC FUNCTYPE
  1306. CCreader(cp)
  1307.     CHANNEL        *cp;
  1308. {
  1309.     static char        TOOLONG[] = "0 Reply too long for server to send";
  1310.     register CCDISPATCH    *dp;
  1311.     register STRING    p;
  1312.     register char    *q;
  1313. #if    defined(DO_HAVE_UNIX_DOMAIN)
  1314.     struct sockaddr_un    client;
  1315. #else
  1316.     int            written;
  1317. #endif    /* defined(DO_HAVE_UNIX_DOMAIN) */
  1318.     int            i;
  1319.     char        buff[BUFSIZ + 2];
  1320.     char        copy[BUFSIZ + 2];
  1321.     char        *argv[SC_MAXFIELDS + 2];
  1322.     int            argc;
  1323.     int            len;
  1324.  
  1325.     if (cp != CCchan) {
  1326.     syslog(L_ERROR, "%s internal CCreader wrong channel 0x%x not 0x%x",
  1327.         LogName, cp, CCchan);
  1328.     return;
  1329.     }
  1330.  
  1331.     /* Get the message. */
  1332.     i = RECVorREAD(CCchan->fd, buff, sizeof buff - 1);
  1333.     if (i < 0) {
  1334.     syslog(L_ERROR, "%s cant recv CCreader %m", LogName);
  1335.     return;
  1336.     }
  1337.     if (i == 0) {
  1338.     syslog(L_ERROR, "%s cant recv CCreader empty", LogName);
  1339.     return;
  1340.     }
  1341.     buff[i] = '\0';
  1342.  
  1343.     /* Copy to a printable buffer, and log. */
  1344.     (void)strcpy(copy, buff);
  1345.     for (p = NULL, q = copy; *q; q++)
  1346.     if (*q == SC_SEP) {
  1347.         *q = ':';
  1348.         if (p == NULL)
  1349.         p = q + 1;
  1350.     }
  1351.     syslog(L_CC_CMD, "%s", p ? p : copy);
  1352.  
  1353.     /* Split up the fields, get the command letter. */
  1354.     if ((argc = CCargsplit(buff, &buff[i], argv, SIZEOF(argv))) < 2
  1355.      || argc == SIZEOF(argv)) {
  1356.     syslog(L_ERROR, "%s bad_fields CCreader", LogName);
  1357.     return;
  1358.     }
  1359.     p = argv[1];
  1360.     i = *p;
  1361.  
  1362.     /* Dispatch to the command function. */
  1363.     for (argc -= 2, dp = CCcommands; dp < ENDOF(CCcommands); dp++)
  1364.     if (i == dp->Name) {
  1365.         if (argc != dp->argc)
  1366.         p = "1 Wrong number of parameters";
  1367.         else
  1368.         p = (*dp->Function)(&argv[2]);
  1369.         break;
  1370.     }
  1371.     if (dp == ENDOF(CCcommands)) {
  1372.     syslog(L_NOTICE, "%s bad_message %c", LogName, i);
  1373.     p = "1 Bad command";
  1374.     }
  1375.     else if (p == NULL)
  1376.     p = "0 Ok";
  1377.  
  1378.     /* Build the reply address and send the reply. */
  1379.     len = strlen(p);
  1380.  
  1381. #if    defined(DO_HAVE_UNIX_DOMAIN)
  1382.     (void)memset((POINTER)&client, 0, sizeof client);
  1383.     client.sun_family = AF_UNIX;
  1384.     (void)strcpy(client.sun_path, argv[0]);
  1385.     if (sendto(CCwriter, p, len, 0,
  1386.         (struct sockaddr *)&client, AF_UNIX_SOCKSIZE(client)) < 0) {
  1387.     i = errno;
  1388.     syslog(i == ENOENT ? L_NOTICE : L_ERROR,
  1389.         "%s cant sendto CCreader bytes %d %m", LogName, len);
  1390.     if (i == EMSGSIZE)
  1391.         (void)sendto(CCwriter, TOOLONG, STRLEN(TOOLONG), 0,
  1392.         (struct sockaddr *)&client, AF_UNIX_SOCKSIZE(client));
  1393.     }
  1394. #else
  1395.     if ((i = open(argv[0], O_WRONLY)) < 0)
  1396.     syslog(L_ERROR, "%s cant open %s %m", LogName, argv[0]);
  1397.     else {
  1398.     if ((written = write(i, p, len)) != len)
  1399.         if (written < 0)
  1400.         syslog(L_ERROR, "%s cant write %s %m", LogName, argv[0]);
  1401.         else
  1402.         syslog(L_ERROR, "%s cant write %s", LogName, argv[0]);
  1403.     if (close(i) < 0)
  1404.         syslog(L_ERROR, "%s cant close %s %m", LogName, argv[0]);
  1405.     }
  1406. #endif    /* defined(DO_HAVE_UNIX_DOMAIN) */
  1407. }
  1408.  
  1409.  
  1410. /*
  1411. **  Called when a write-in-progress is done on the channel.  Shouldn't happen.
  1412. */
  1413. STATIC FUNCTYPE
  1414. CCwritedone()
  1415. {
  1416.     syslog(L_ERROR, "%s internal CCwritedone", LogName);
  1417. }
  1418.  
  1419.  
  1420. /*
  1421. **  Create the channel.
  1422. */
  1423. void
  1424. CCsetup()
  1425. {
  1426.     int            i;
  1427. #if    defined(DO_HAVE_UNIX_DOMAIN)
  1428.     struct sockaddr_un    server;
  1429. #endif    /* defined(DO_HAVE_UNIX_DOMAIN) */
  1430.  
  1431.     /* Remove old detritus. */
  1432.     if (unlink(CCpath) < 0 && errno != ENOENT) {
  1433.     syslog(L_FATAL, "%s cant unlink %s %m", LogName, CCpath);
  1434.     exit(1);
  1435.     }
  1436.  
  1437. #if    defined(DO_HAVE_UNIX_DOMAIN)
  1438.     /* Create a socket and name it. */
  1439.     if ((i = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
  1440.     syslog(L_FATAL, "%s cant socket %s %m", LogName, CCpath);
  1441.     exit(1);
  1442.     }
  1443.     (void)memset((POINTER)&server, 0, sizeof server);
  1444.     server.sun_family = AF_UNIX;
  1445.     (void)strcpy(server.sun_path, CCpath);
  1446.     if (bind(i, (struct sockaddr *)&server, AF_UNIX_SOCKSIZE(server)) < 0) {
  1447.     syslog(L_FATAL, "%s cant bind %s %m", LogName, CCpath);
  1448.     exit(1);
  1449.     }
  1450.  
  1451.     /* Create an unbound socket to reply on. */
  1452.     if ((CCwriter = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
  1453.     syslog(L_FATAL, "%s cant socket unbound %m", LogName);
  1454.     exit(1);
  1455.     }
  1456. #else
  1457.     /* Create a named pipe and open it. */
  1458.     if (mkfifo(CCpath, 0666) < 0) {
  1459.     syslog(L_FATAL, "%s cant mkfifo %s %m", LogName, CCpath);
  1460.     exit(1);
  1461.     }
  1462.     if ((i = open(CCpath, O_RDWR)) < 0) {
  1463.     syslog(L_FATAL, "%s cant open %s %m", LogName, CCpath);
  1464.     exit(1);
  1465.     }
  1466. #endif    /* defined(DO_HAVE_UNIX_DOMAIN) */
  1467.  
  1468.     CCchan = CHANcreate(i, CTcontrol, CSwaiting, CCreader, CCwritedone);
  1469.     syslog(L_NOTICE, "%s ccsetup %s", LogName, CHANname(CCchan));
  1470.     RCHANadd(CCchan);
  1471.  
  1472.     CCreply.Size = SMBUF;
  1473.     CCreply.Data = NEW(char, CCreply.Size);
  1474. }
  1475.  
  1476.  
  1477. /*
  1478. **  Cleanly shut down the channel.
  1479. */
  1480. void
  1481. CCclose()
  1482. {
  1483.     CHANclose(CCchan, CHANname(CCchan));
  1484.     CCchan = NULL;
  1485.     if (unlink(CCpath) < 0)
  1486.     syslog(L_ERROR, "%s cant unlink %s %m", LogName, CCpath);
  1487. #if    defined(DO_HAVE_UNIX_DOMAIN)
  1488.     if (close(CCwriter) < 0)
  1489.     syslog(L_ERROR, "%s cant close unbound %m", LogName);
  1490. #endif    /* defined(DO_HAVE_UNIX_DOMAIN) */
  1491. }
  1492.